package com.yixiang.np.logaop;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.yixiang.np.annotation.SystemControllerLog;
import com.yixiang.np.annotation.SystemServiceLog;
import com.yixiang.np.constant.GlobalConstant;
import com.yixiang.np.dao.LogDao;
import com.yixiang.np.model.SessionInfo;
 
/**
 * 切点类
 * @version 1.0
 */
@Aspect
@Component
public  class LogAopAction {
    //本地异常日志记录对象
	@Autowired
    public LogDao logDao;
	@Autowired
	private HttpServletRequest request;
    //Controller层切点
    @Pointcut("@annotation(com.yixiang.np.annotation.SystemControllerLog)")
    public  void controllerAspect() {
    }
    //Service层切点    
    @Pointcut("@annotation(com.yixiang.np.annotation.SystemServiceLog)")    
     public  void serviceAspect() {    
    }    
    
    /**
     * 操作异常记录
     *@descript
     *@param point
     *@param e
     *@version 1.0
     */
    @AfterThrowing(pointcut = "controllerAspect()", throwing = "e")  
    public  void doAfterThrowing(JoinPoint point, Throwable e) {  
    	Map<String, Object> logForm = new HashMap<String, Object>();
		Map<String, Object> map = null;
		String user = null;
		String userid = null;
		String ip = null;
		try {
			ip = request.getRemoteAddr(); 
		} catch (Exception ee) {
			ip = "无法获取登录用户Ip";
		}
		try {
			SessionInfo sessionInfo = (SessionInfo) request.getSession().getAttribute(GlobalConstant.SESSION_INFO);
			map = getControllerMethodDescription(point);
			// 登录名
			userid = sessionInfo.getId().toString();
			user = sessionInfo.getName();
			if (StringUtils.isEmpty(user)) {
				user = "无法获取登录用户信息！";
			}
		} catch (Exception ee) {
			user = "无法获取登录用户信息！";
		}
		logForm.put("userid",userid);
    	logForm.put("username",user);
    	logForm.put("ip",ip);
    	logForm.put("params",map.get("params"));
		logForm.put("module",map.get("module"));
		logForm.put("methods","<font color=\"red\">执行方法异常:-->"+map.get("methods")+"</font>");
		logForm.put("descriptions","<font color=\"red\">执行方法异常:-->"+e+"</font>");
		logForm.put("createtime",new Date());
		try {
			logDao.addEntity(logForm);
		} catch (Exception e1) {
			e1.printStackTrace();
		}
    }
    /**
     * 前置通知 用于拦截Controller层记录用户的操作
     * @param joinPoint 切点
     */
    @Around("controllerAspect()")
     public Object doController(ProceedingJoinPoint point) {
    	Object result = null;
		// 执行方法名
		String methodName = point.getSignature().getName();
		String className = point.getTarget().getClass().getSimpleName();
		Map<String, Object> logForm = new HashMap<String, Object>();
		Map<String, Object> map = null;
		String userid = null;
		String user = null;
		Long start = 0L;
		Long end = 0L;
		Long time = 0L;
		String ip = null;
		try {
			ip = request.getRemoteAddr(); 
		} catch (Exception ee) {
			ip = "无法获取登录用户Ip";
		}
		try {
			SessionInfo sessionInfo = (SessionInfo) request.getSession().getAttribute(GlobalConstant.SESSION_INFO);
			// 登录名
			userid = sessionInfo.getId().toString();
			user = sessionInfo.getName();
			if (StringUtils.isEmpty(user)) {
				user = "无法获取登录用户信息！";
			}
		} catch (Exception e) {
			user = "无法获取登录用户信息！";
		}
		// 当前用户
		try {
			map=getControllerMethodDescription(point);
			// 执行方法所消耗的时间
			start = System.currentTimeMillis();
			result = point.proceed();
			end = System.currentTimeMillis();
		    time = end - start;
		} catch (Throwable e) {
			throw new RuntimeException(e);
		}
         try {
        	 logForm.put("userid",userid);
         	logForm.put("username",user);
         	logForm.put("ip",ip);
         	logForm.put("params",map.get("params"));
 			logForm.put("module",map.get("module"));
 			logForm.put("methods",map.get("methods"));
 			logForm.put("descriptions",map.get("descriptions"));
 			logForm.put("createtime",new Date());
 			logDao.addEntity(logForm);
            //*========控制台输出=========*//
            System.out.println("=====通知开始=====");
            System.out.println("请求方法:" + className + "." + methodName + "()");
            System.out.println("方法描述:" + map);
            System.out.println("请求IP:" + ip);
            System.out.println("=====通知结束=====");
        }  catch (Exception e) {
            //记录本地异常日志
        	e.printStackTrace();
        }
         return result;
    }
    
    /**
     * 前置通知 用于拦截service层记录用户的操作
     * @param joinPoint 切点
     */
    @Around("serviceAspect()")
     public Object doService(ProceedingJoinPoint point) {
    	Object result = null;
		// 执行方法名
		String methodName = point.getSignature().getName();
		String className = point.getTarget().getClass().getSimpleName();
		Map<String, Object> logForm = new HashMap<String, Object>();
		Map<String, Object> map = null;
		String userid = null;
		String user = null;
		Long start = 0L;
		Long end = 0L;
		Long time = 0L;
		String ip = null;
		try {
			ip = request.getRemoteAddr(); 
		} catch (Exception ee) {
			ip = "无法获取登录用户Ip";
		}
		try {
			SessionInfo sessionInfo = (SessionInfo) request.getSession().getAttribute(GlobalConstant.SESSION_INFO);
			// 登录名
			userid = sessionInfo.getId().toString();
			user = sessionInfo.getName();
			if (StringUtils.isEmpty(user)) {
				user = "无法获取登录用户信息！";
			}
		} catch (Exception e) {
			user = "无法获取登录用户信息！";
		}
		// 当前用户
		try {
			map=getServiceMethodDescription(point);
			// 执行方法所消耗的时间
			start = System.currentTimeMillis();
			result = point.proceed();
			end = System.currentTimeMillis();
		    time = end - start;
		} catch (Throwable e) {
			throw new RuntimeException(e);
		}
         try {
        	 logForm.put("userid",userid);
         	logForm.put("username",user);
         	logForm.put("ip",ip);
         	logForm.put("params",map.get("params"));
 			logForm.put("module",map.get("module"));
 			logForm.put("methods",map.get("methods"));
 			logForm.put("descriptions",map.get("descriptions"));
 			logForm.put("createtime",new Date());
 			logDao.addEntity(logForm);
            //*========控制台输出=========*//
            System.out.println("=====通知开始=====");
            System.out.println("请求方法:" + className + "." + methodName + "()");
            System.out.println("方法描述:" + map);
            System.out.println("请求IP:" + ip);
            System.out.println("=====通知结束=====");
        }  catch (Exception e) {
            //记录本地异常日志
        	e.printStackTrace();
        }
         return result;
    }
    /**
     * 获取注解中对方法的描述信息 用于Controller层注解
     * @param joinPoint 切点
     * @return 方法描述
     * @throws Exception
     */
     @SuppressWarnings("rawtypes")
	public Map<String, Object> getControllerMethodDescription(JoinPoint joinPoint)  throws Exception {
    	// 获取签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method meth = signature.getMethod();
        SystemControllerLog annotation = meth.getAnnotation(SystemControllerLog.class);
        
    	Map<String, Object> map = new HashMap<String, Object>();
    	String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        // 记录日志
        Object[] arguments = joinPoint.getArgs();
        // 抽取出方法描述：
        String paramDesc = extractParam(arguments);
        if(paramDesc != null && paramDesc.length()>4000){
        	paramDesc = paramDesc.substring(0, 2000);
        }
        map.put("params", paramDesc);
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
         for (Method method : methods) {
             if (method.getName().equals(methodName)) {
                Class[] clazzs = method.getParameterTypes();
                 if (clazzs.length == arguments.length) {
                	 map.put("module", method.getAnnotation(SystemControllerLog.class).module());
                	 map.put("methods", method.getAnnotation(SystemControllerLog.class).methods());
                	 String de = method.getAnnotation(SystemControllerLog.class).description();
                	 if(StringUtils.isEmpty(de))de="执行成功!";
                	 map.put("descriptions", de);
                     break;
                }
            }
        }
         return map;
    }
     @SuppressWarnings("rawtypes")
     public Map<String, Object> getServiceMethodDescription(JoinPoint joinPoint)  throws Exception {
    	 // 获取签名
    	 MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    	 Method meth = signature.getMethod();
    	 SystemServiceLog annotation = meth.getAnnotation(SystemServiceLog.class);
    	 
    	 Map<String, Object> map = new HashMap<String, Object>();
    	 String targetName = joinPoint.getTarget().getClass().getName();
    	 String methodName = joinPoint.getSignature().getName();
    	 // 记录日志
    	 Object[] arguments = joinPoint.getArgs();
    	 // 抽取出方法描述：
    	 String paramDesc = extractParam(arguments);
    	 map.put("params", paramDesc);
    	 Class targetClass = Class.forName(targetName);
    	 Method[] methods = targetClass.getMethods();
    	 for (Method method : methods) {
    		 if (method.getName().equals(methodName)) {
    			 Class[] clazzs = method.getParameterTypes();
    			 if (clazzs.length == arguments.length) {
    				 map.put("module", method.getAnnotation(SystemServiceLog.class).module());
    				 map.put("methods", method.getAnnotation(SystemServiceLog.class).methods());
    				 String de = method.getAnnotation(SystemServiceLog.class).description();
    				 if(StringUtils.isEmpty(de))de="执行成功!";
    				 map.put("descriptions", de);
    				 break;
    			 }
    		 }
    	 }
    	 return map;
     }
     
     /**
      * 根据注解参数以及方法实参拼接出方法描述
      * @param objParam
      * @param arguDesc
      * @return
      */
     private String extractParam(Object[] objParam) {
    	 StringBuilder paramSb = new StringBuilder();
    	 try {
    	         int size = objParam.length-1;
    	         for (int i = 0; i < objParam.length; i++) {
//    	             paramSb.append(objParam[i]+":"+objParam[i]+(i==size?"":","));
    	        	try {
    	        		 paramSb.append(JSONObject.toJSONString(objParam[i]) + ";");
					} catch (Exception e) {
						// TODO: handle exception
					}
    	         }
		} catch (Exception e) {
			e.printStackTrace();
		}
         return paramSb.toString();
     }
}
